package com.fusetech.flow.audit.supportService.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fusetech.common.core.domain.entity.SysRole;
import com.fusetech.common.core.domain.entity.SysUser;
import com.fusetech.flow.audit.domain.*;
import com.fusetech.flow.audit.model.Audit;
import com.fusetech.flow.audit.model.AuditResponse;
import com.fusetech.flow.audit.model.CheckResponse;
import com.fusetech.flow.audit.service.*;
import com.fusetech.flow.audit.service.dto.AuditNodeDTO;
import com.fusetech.flow.audit.service.dto.CurrentAuditNodeDTO;
import com.fusetech.flow.audit.supportService.IAuditChcekService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 审计服务chcek impl
 *
 * @author Liuwq
 * @Author：Liuwq-Fuse
 * @Package：com.zxhy.service.erp.audit.supportService.impl
 * @Project：zhixing-heyue-erp-server-dev
 * @name：AuditChcekServiceImpl
 * @Date：2023/6/5 14:26
 * @Filename：AuditChcekServiceImpl
 * @date 2023/06/05
 */
@Service
@Transactional
@Primary
public class AuditChcekServiceImpl implements IAuditChcekService {
    @Autowired
    private AuditProcessAuditorRoleUserService auditProcessAuditorRoleUserService;
    @Autowired
    private AuditNodeAuditorService auditNodeAuditorService;
    @Autowired
    private AuditNodeAuditorRoleUserService auditNodeAuditorRoleUserService;
    @Autowired
    private CurrentAuditNodeService currentAuditNodeService;
    @Autowired
    private AuditProcessService auditProcessService;
    @Autowired
    private AuditProcessFormService auditProcessFormService;
    /**
     * 异常信息
     */
    private String errMsg;

    public String getErrMsg() {
        return errMsg;
    }

    public void setErrMsg(String errMsg) {
        this.errMsg = errMsg;
    }
    /**
     * 检查节点用户roleb
     *
     * @param list       列表
     * @param user       用户
     * @param documentId 文档id
     * @return boolean
     */
    public boolean checkNodeUserRoleB(List<SysRole> list, SysUser user, String documentId) {
        //CheckResponse checkResponse = new CheckResponse();
        CurrentAuditNodeDTO currentAuditNodeDTO = currentAuditNodeService.getCurrentAuditNodeDTOByDocumentId(documentId);
        if(!ObjectUtils.isEmpty(currentAuditNodeDTO)){
            AuditNodeDTO an = currentAuditNodeDTO.getAuditNode();

            QueryWrapper query = new QueryWrapper();
            query.eq("audit_node", an.getId());
            List<AuditNodeAuditorRoleUser> nodeAuditorRoleList = auditNodeAuditorRoleUserService.list(query);

            if (isNodeCheckHas(list, nodeAuditorRoleList)) {//先判断节点角色权限
                return true;
            } else {//再判断用户权限
                QueryWrapper queryAuditor = new QueryWrapper();
                queryAuditor.eq("audit_node", an.getId());
                List<AuditNodeAuditor> nodeAuditorList = auditNodeAuditorService.list(queryAuditor);
                if (isNodeCheckAuditorHas(user.getUserId().toString(), nodeAuditorList)) {//[框架对应转换]
                    return true;
                }
                return false;
            }
        }
        return false;
    }

    /**
     * 检验用户是否有当前节点审核权限
     *
     * @return
     */
    public CheckResponse checkNodeUserRole(List<SysRole> list, SysUser user, String documentId) {
        CheckResponse checkResponse = new CheckResponse();
        CurrentAuditNodeDTO currentAuditNodeDTO = currentAuditNodeService.getCurrentAuditNodeDTOByDocumentId(documentId);
        if(!ObjectUtils.isEmpty(currentAuditNodeDTO)){
            AuditNodeDTO an = currentAuditNodeDTO.getAuditNode();

            QueryWrapper query = new QueryWrapper();
            query.eq("audit_node", an.getId());
            List<AuditNodeAuditorRoleUser> nodeAuditorRoleList = auditNodeAuditorRoleUserService.list(query);

            if (isNodeCheckHas(list, nodeAuditorRoleList)) {//先判断节点角色权限
                checkResponse.setFlag(true);
                //return true;
            } else {//再判断用户权限
                QueryWrapper queryAuditor = new QueryWrapper();
                queryAuditor.eq("audit_node", an.getId());
                List<AuditNodeAuditor> nodeAuditorList = auditNodeAuditorService.list(queryAuditor);
                if (isNodeCheckAuditorHas(user.getUserId().toString(), nodeAuditorList)) {//[框架对应转换]
                    checkResponse.setFlag(true);
                    //return true;
                }
                checkResponse.setFlag(false);
                checkResponse.setErrMsg("该用户没有当前节点审核权限");
                //return false;
            }
        }else {
            checkResponse.setFlag(false);//该表单没有对应当前节点
            checkResponse.setErrMsg("该表单没有对应当前节点");
        }
        return checkResponse;
    }

    /**
     * 检验用户是否有流程进入权限
     */
    public boolean checkProcessUserRole(List<SysRole> list, String documentType) {
        AuditProcess auditProcess = getAuditProcessByDocumentType(documentType);
        String processId = auditProcess.getId();
        QueryWrapper queryRole = new QueryWrapper();
        queryRole.eq("audit_process", processId);
        List<AuditProcessAuditorRoleUser> auditorRoleList = auditProcessAuditorRoleUserService.list(queryRole);
        return isALLCheckHas(list, auditorRoleList);
    }

    /**
     * 检查用户角色
     *
     * @param list         列表
     * @param documentType 文档类型
     * @return {@link CheckResponse}
     */
    public CheckResponse checkProcessUserRoleResponse(List<SysRole> list, String documentType) {
        CheckResponse checkResponse = new CheckResponse();
        AuditProcess auditProcess = getAuditProcessByDocumentType(documentType);
        if(!ObjectUtils.isEmpty(auditProcess)){
            String processId = auditProcess.getId();
            QueryWrapper queryRole = new QueryWrapper();
            queryRole.eq("audit_process", processId);
            List<AuditProcessAuditorRoleUser> auditorRoleList = auditProcessAuditorRoleUserService.list(queryRole);
            Boolean b = isALLCheckHas(list, auditorRoleList);
            if(b){
                checkResponse.setFlag(true);
            }else {
                checkResponse.setFlag(false);//该表单没有对应当前节点
                checkResponse.setErrMsg("该用户没有当前类型流程初始审核权限");
            }
        }else {
            checkResponse.setFlag(false);//该表单没有对应当前节点
            checkResponse.setErrMsg("该类型没有对应的流程配置");
        }
        return checkResponse;
    }

    static boolean isALLCheckHas(List<SysRole> list, List<AuditProcessAuditorRoleUser> auditorRoleList) {
        //将列表中需要比较的对象拿出来
        List<Long> userRoleList = list.stream().map(SysRole::getRoleId).collect(Collectors.toList());//[框架对应转换]
        List<String> PZRoleList = auditorRoleList.stream().map(AuditProcessAuditorRoleUser::getAuditorRoleUserId).collect(Collectors.toList());
        List listJG = userRoleList.stream().filter(str -> PZRoleList.contains(str)).collect(Collectors.toList());
        if (null != listJG && listJG.size() > 0) {
            return true;
        } else {
            return false;
        }
    }

    static boolean isNodeCheckHas(List<SysRole> list, List<AuditNodeAuditorRoleUser> auditorRoleList) {
        //将列表中需要比较的对象拿出来
        List<Long> userRoleList = list.stream().map(SysRole::getRoleId).collect(Collectors.toList());//[框架对应转换]
        List<String> PZRoleList = auditorRoleList.stream().map(AuditNodeAuditorRoleUser::getAuditorRoleUser).collect(Collectors.toList());
        List listJG = userRoleList.stream().filter(str -> PZRoleList.contains(str)).collect(Collectors.toList());
        if (null != listJG && listJG.size() > 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 节点检查审计
     *
     * @param userId          用户id
     * @param auditorRoleList 审计师角色列表
     * @return boolean
     * @author Liuwq
     * @date 2023/06/14
     */
    static boolean isNodeCheckAuditorHas(String userId, List<AuditNodeAuditor> auditorRoleList) {
        //将列表中需要比较的对象拿出来
        List<String> PZRoleList = auditorRoleList.stream().map(AuditNodeAuditor::getAuditor).collect(Collectors.toList());
        return PZRoleList.contains(userId);
    }

    /**
     * 文档类型get AuditProcess
     *
     * @param documentType 文档类型
     * @return {@link AuditProcess}
     */
    AuditProcess getAuditProcessByDocumentType(String documentType)  {
        this.errMsg = new String();
        AuditProcess auditProcess =new AuditProcess();
        QueryWrapper queryForm = new QueryWrapper();
        queryForm.eq("form_id", documentType);
        List<AuditProcessForm> form = auditProcessFormService.list(queryForm);//避免数据库数据不正常时报错，取list
        if(CollectionUtil.isNotEmpty(form)){
            auditProcess = auditProcessService.getById(form.get(0).getAuditProcessId());
        }else {
            //throw new ServiceException("该表单场景没有配置对应流程，请在配置中添加");
            //System.out.println("该表单场景没有配置对应流程，请在配置中添加");
            setErrMsg("该表单场景没有配置对应流程，请在配置中添加");
        }
        return auditProcess;
    }

    /**
     * 检查传入审核参数
     *
     * @param audit    审计
     * @param response 响应
     * @return {@link AuditResponse}
     */
    public AuditResponse checkAuditParam(Audit audit, AuditResponse response){
        response.setCode("200");
        if(ObjectUtil.isEmpty(audit.getDocumentId())){
            response.setCode("500");
            response.setMsg("DocumentId不能为空！");
            //throw new RuntimeException("");
        }
        if(ObjectUtil.isEmpty(audit.getDocumentType())){
            response.setCode("500");
            response.setMsg("DocumentType不能为空！");
        }
        if(ObjectUtil.isEmpty(audit.getAuditor())){
            response.setCode("500");
            response.setMsg("审核人不能为空！否则无法检验权限");
        }
        if(ObjectUtil.isEmpty(audit.getListSysRole())){
            response.setCode("500");
            response.setMsg("审核角色不能为空！否则无法检验权限");
        }
        return response;
    }


}
